package graph;

import com.sun.org.apache.regexp.internal.RE;
import sun.applet.Main;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * @Author Zhouchb
 * @Create 2021-10-2021/10/30 :10:47
 * @Description
 */
public class Graphjuzheng {
   private ArrayList<String> vertexList;//存储顶点集合
    private int[][] edges;//存储图对应的玲姐矩阵
    private int numOfEdges;//表示表的数目;
    //定义给数据boolean[],记录某个结点是否被访问
    private boolean[] isVisited ;
    public static void main(String[] args) {
    //测试图
        int n = 5;//结点的个数
        String Vertexs[] = {"A","B","C","D","E"};
        //创建图对象
        Graphjuzheng graph = new Graphjuzheng(n);
        //循环添加顶点
        for (String Vertex : Vertexs) {
        graph.insertVertex(Vertex);
        }
        //添加边
        graph.insertEdge(0,1,1);
        graph.insertEdge(0,2,1);
        graph.insertEdge(1,2,1);
        graph.insertEdge(1,3,1);
        graph.insertEdge(1,4,1);
        //显示邻接矩阵
        graph.showGraph();
        graph.bfs();
    }

    //构造器
    public Graphjuzheng(int n){
        //初始化矩阵和vertexList
        edges = new int[n][n];
        vertexList = new ArrayList<String>(n);
        numOfEdges = 0;
       this.isVisited = new boolean[n];
    }
    //图中常用的方法
    //返回结点的个数
    public int getNumOfVertex(){
        return vertexList.size();
    }
//得到边的个数
    public int getNumOfEdges(){
        return numOfEdges;
    }
    //返回结点i对应的数据 0-》A，1->B
    public String getValueByIndex(int i){
        return vertexList.get(i);
    }
    //返回v1和v2的权值
    public int getWeight(int v1,int v2){
        return edges[v1][v2];
    }
    //插入结点
    public void insertVertex(String vertex){
        vertexList.add(vertex);
    }
    //添加边  v1,v2二位数组的下标   weight 1/0
    public void insertEdge(int v1,int v2,int weight){
        edges[v1][v2] = weight;
        edges[v2][v1] = weight;
        numOfEdges++;
    }
    //显示图对应的矩阵
    public void showGraph(){
        for (int[] link:edges){
            System.out.println(Arrays.toString(link));
        }
    }

    //得到第一个邻接点的下标
    public int getFirstNeighbor(int index){
        for (int j=0;j<vertexList.size();j++){
            if (edges[index][j]>0){
                return j;
            }
        }
        return -1;
    }

    //对一个结点进行广度优先遍历
    private void bfs(boolean[] isVisited,int i){
        int u;//表示队列头结点对应下标
        int w;//邻接结点w
        //队列，结点访问的顺序
        LinkedList<Object> queue = new LinkedList<>();
        //访问结点，输出结点信息
        System.out.println(getValueByIndex(i)+"->");
        //标记为已访问
        isVisited[i]=true;
        //将结点加入队列
        queue.add(i);

        while (!queue.isEmpty()){
            //取出队列的头结点下标
            u = (Integer) queue.removeFirst();
            //得到第一个邻接点的下标
            w = getFirstNeighbor(u);
            while (w!=-1){//找到
                //是否访问过
                if (!isVisited[w]){
                    System.out.print(getValueByIndex(w)+"->");
                    //标记已经访问
                    isVisited[w]=true;
                    //入队
                    queue.addLast(w);
                }
                //以u为前驱，找w后面的下一个邻接点
                w = getNextNeighbor(u,w);//体现广度优先
            }

        }
    }
//根据前一个邻接结点的下标来获取下一个邻接结点
    public int getNextNeighbor(int v1,int v2){
        for (int j=v2+1;j<vertexList.size();j++){
            if (edges[v1][j]>0){
                return j;
            }
        }return -1;
    }
    //遍历所有结点，进行广度优先搜索
    public void bfs(){

        for (int i =0;i<getNumOfVertex();i++){
            if (!isVisited[i]){
                bfs(isVisited,i);
            }
        }
    }
}
